Tutorial

Furniture Application with React Native

8 steps

Have you ever wondered how mobile application pages work? How can you as a developer create a multi-page application? Well, you are at the right place! Today, we will be learning how to create our very own multi-page mobile application with React Navigation. In the ReactJS skill, we explored React Router for a multi-page web browsing experience. Similar to React Router, React Navigation is a popular dependency frontend developers use to make multi-page native applications.

We will be making a two-page furniture ordering application. The first page will be for browsing and the next page will be for ordering the furniture we want. We will also learn about other components that are shipped with React Native. One of the components is ScrollView, which is a View component that will allow you to make scrollable components. Sometimes when you have a long list of items and you want to go through them, we will use ScrollView as it will allow us to adjust the areas that are viewable by the users.

Watch the video below to have an idea of what you will be building.

Learning Outcomes

By the end of this tutorial, you will be able to:

  1. Apply the map() function to iterate through an array
  2. Build a multi-page mobile application with React Navigation
  3. Pass data between various pages
  4. Load static data locally

Tutorial Steps

Total steps: 8

  • Step 1: Project Setup

    In this step, we will be setting up our environment to develop our furniture application. Firstly, open a code editor of your choice. Select a folder as your project root folder and open up your terminal.

    Enter the following commands one by one in your computer’s terminal.

    npm i expo-cli -g
    npx expo init furniture-app
    cd furniture-app
    npm install @react-navigation/native @react-navigation/native-stack
    npx expo install react-native-screens react-native-safe-area-context
    npx expo start

    The code shown above is a set of commands to set up a basic React Native app using the Expo framework.

    The second command npx expo init furniture-app initializes a new project using the Expo CLI, with the project name "furniture-app". The npx command is used to execute a package without the need to install it globally on your system. When prompted, you should select the option for a blank template.

    The third command, cd furniture-app, changes the current working directory to the newly created project folder. This is necessary to access the project files and run further commands.

    The fourth and fifth commands npm install @react-navigation/native @react-navigation/native-stack and npx expo install react-native-screens react-native-safe-area-context install the necessary dependencies for the app.

    The packages @react-navigation/native and @react-navigation/native-stack provide routing and navigation functionality for React Native apps. The react-native-screens and react-native-safe-area-context packages are used to implement native-like navigation and user interfaces.

    Finally, the command npx expo start starts the development server and launches the app in the browser or on a connected device. This command uses the Expo CLI to start the app and preview it.

  • Step 2: File and Folder Management

    Once we are done with downloading the dependencies, we will move on to creating some files and folders. First, in the furniture-app folder, create a subfolder called pages. In the pages subfolder, create 2 new files, IndexPage.js and DetailPage.js. These are the files we will be working with to display the two pages. Next, in the furniture-app folder, create another file named Content.js. This file will contain the furniture we use for this project.

    As you may realise, Expo has installed and created the node_modules folder which contains all of the dependencies we need for this React Native project. The assets folder will be where you will be able to add your own images. Any time when you want to use images from this folder, you should make the image path you are referencing relative to this folder.

    Lastly, App.js will be the entry file that React Native will first interact with.

    To check if you have added the files in the right folders, check the image below.

  • Step 3: Content Page and View Management

    In the ReactJS module, the blog and recipe web applications used a similar concept, where a file is used as a contents page. This means that this file will store all of the various pages that are within our mobile application. For React Native, we will need to use the App.js file, which we will start coding in.

    Add the following code snippet after line 2 of the file.

    import { NavigationContainer } from '@react-navigation/native';
    import { createNativeStackNavigator } from '@react-navigation/native-stack';
    import IndexPage from './pages/IndexPage';
    
    const Stack = createNativeStackNavigator();
    JavaScript

    In the code snippet above, we are importing the dependencies that we installed in Step 1. These dependencies from React Navigation will be used to control what the user is seeing on their screen.

    In React Navigation, there are various types of navigation such as Bottom Tabs Navigation, Stack Navigation and Drawer Navigation.

    The Bottom Tabs Navigation is designed for applications that have a small number of screens and require quick and easy navigation between them. This type of navigation displays a set of tabs at the bottom of the screen, allowing users to switch between different screens with a single tap.

    The Stack Navigation is useful for navigating between screens that follow a stack-like structure, where a new screen is added on top of the previous one. This type of navigation is often used to implement a back button in your app, allowing users to easily navigate back to previous screens.

    The Drawer Navigation provides a hidden menu that can be accessed by tapping on a menu icon, typically located in the top left or top right of the screen. This type of navigation is often used to provide quick access to different sections of an application, making it easy for users to find what they are looking for.

    Each of these navigation types can be customized and tailored to meet the specific needs of your application. By choosing the right type of navigation for your app, you can ensure that your users have a smooth and intuitive experience while navigating through your app. We will be using the Stack Navigation. The Stack Navigation is basic and easy to implement.

    Replace the code found within the return statement with the code snippet below.

    <NavigationContainer>
       <Stack.Navigator>
        <Stack.Screen name="Index" component={IndexPage} options={{headerShown:false}}/>
       </Stack.Navigator>
      </NavigationContainer>
    JavaScript

    To check if you have added the code correctly to your file so far, you may refer to the image below. Also, if you are referring to your phone and see a render error at this point, don't worry. As we add more lines of code, we will be able to see the finished product at the end.

    To set up a Stack Navigation, the NavigationContainer component is the top-level component provided by the React Navigation library that manages the navigation state for your entire app.

    Within the NavigationContainer component in line 12, a Stack.Navigator component is used to wrap the screens that will be managed by the Stack Navigation type. The Stack.Navigator component is responsible for controlling the stack-based navigation of your application.

    The Stack.Screen component (line 13) is used to define a single screen within the stack-based navigation. Each Stack.Screen component must have a unique name prop, which is used to refer to that specific screen within the stack, and a component prop, which is the React component that will be rendered for that screen.

    In this example, there is only one Stack.Screen component defined, with a name of Index and a component of IndexPage. This means that when the navigation stack is at this screen, the IndexPage component will be rendered.

    Each time we create a new page, each page needs to have their own Stack.Screen element. The 2 crucial props we will need to add in are the name and the component props. In any project, each page should have a unique name. There should not be any screens with the same name prop.

  • Step 4: Content Setup

    Before we start creating our first page, we will need to generate some local data. The local data will allow us to populate various information onto our application. This will also simulate how we can display data we receive from a server. Open the Content.js file and enter the code below.

    export const data = [
      {
        "id": 1,
        "name": "Wooden Chair",
        "price": 100,
        "description": "Built with the finest wood in Greece. Handcrafted by the best craftsmen in the world.",
        "image": require("./assets/chair.jpg"),
        "color":["#000000", "#FFFFFF", "#FF0000", "#00FF00", "#0000FF"]
      },
      {
        "id": 2,
        "name": "Wooden Table",
        "price": 200,
        "description": "Built with the finest wood in Greece. Handcrafted by the best craftsmen in the world.",
        "image": require("./assets/table.jpg"),
        "color":["#000000", "#FFFFFF", "#FF0000", "#00FF00", "#0000FF"]
      },
      {
        "id": 3,
        "name": "Leather Sofa",
        "price": 3500,
        "description": "The material is made from the finest leather in the world. Handcrafted by the best craftsmen in the world.",
        "image": require("./assets/sofa.jpg"),
        "color":["#000000", "#FFFFFF", "#FF0000", "#00FF00", "#0000FF"]
      },
      {
        "id": 4,
        "name": "Shelves",
        "price": 400,
        "description": "Built with the finest wood in Greece. Handcrafted by the best craftsmen in the world.",
        "image": require("./assets/shelves.jpg"),
        "color":["#000000", "#FFFFFF", "#FF0000", "#00FF00", "#0000FF"]
      },
      {
        "id": 5,
        "name": "Bed",
        "price": 1000,
        "description": "Built with the finest wood in Greece. Handcrafted by the best craftsmen in the world.",
        "image": require("./assets/bed.jpg"),
        "color":["#000000", "#FFFFFF", "#FF0000", "#00FF00", "#0000FF"]
      }
    ]
    JavaScript

    In this code, we created a constant named data which contains 5 objects that can be imported by other files. They contain furniture data that can be displayed. In this example, we will work with arrays, integers and strings to display them onto our frontend. Each object has properties that we can use to display on the front-end. In particular, notice that each of the object has an image key, and their value are image names. If you check your assets folder, you will notice that these images are not present. For your submission, you will need to find five images and give them filenames as referenced such as chair.jpg and table.jpg.

  • Step 5: IndexPage.js

    Now, we will be creating the index page of the mobile application. We will need to import the static data from Content.js. In this manner, we will be able to dynamically output the data to the frontend.

    Open the IndexPage.js file and add the code as shown in the snippet below.

    import { SafeAreaView, View, StyleSheet, Text, ScrollView, Image, TouchableOpacity, StatusBar } from "react-native";
    import { data } from "../Content";
    
    const IndexPage = ({navigation}) => {
      return (
        <View style={{flex:1, marginTop: StatusBar.currentHeight}}>
          {/* Header */}
          <View style={styles.header}>
            <SafeAreaView>
              <Text style={styles.headerText}>Stackie's Furniture</Text>
              <Text style={{...styles.headerText, fontSize:15}}>The best furniture in the world</Text>
            </SafeAreaView>
          </View>
          {/* Scrollview */}
          <ScrollView style={{flexGrow:0, flexShrink:1}}>
            {data.map((item, index) => {
              return (
                <TouchableOpacity 
                  key={index} 
                  style={styles.container}
                  onPress={() => navigation.navigate("DetailPage", {item})}
                >
                  <Image style={styles.image} source={item.image} />
                  <View style={styles.innerImage}>
                    <Text style={styles.text}>{item.name}</Text>
                    <Text style={{...styles.text, color:"gray"}}>${addCommas(item.price)}</Text>
                  </View>
                </TouchableOpacity>
              )
            })}
          </ScrollView>
        </View>
      );
    }
     
    export default IndexPage;
    JavaScript

    The code above is responsible for the structure of our application. We will need to import every component we use from the “react-native” library. You may notice that in line 4, we have {navigation} passed into the functional page components, in this example, it is IndexPage(). This is available as we are using React Navigation which we installed in Step 1. It allows us to use the navigation object to navigate to any page we want to.

    Add the code below after the function has been written (after line 4).

    const addCommas = (num) => {
        return new Intl.NumberFormat("en-US",{
          style: "decimal",
          maximumFractionDigits: 2,
          minimumFractionDigits: 2,
          currency: "USD"
        }).format(num);
      }
    JavaScript

    The function addCommas takes in a number and returns it formatted as a currency using the Internationalization API. The returned number will have a maximum of 2 decimal places, minimum of 2 decimal places and a currency symbol of USD.

    To ensure that we are able to use the Internationalization API, we will need to install its package using the following command in your terminal. If you have Expo currently running in your terminal, open a new terminal.

    npm i intl

    The View component (line 15) has a view with a flex value of 1. This means that the component should expand to fill all available space in its parent container. This property specifies that the component should take up as much space as it can within its parent container along the main axis. If there are multiple components with the same flex property in the same container, then they will be sized based on their relative proportion of the available space. You can refer to this documentation.

    Within this view, there are two parts, a header and a scrollview. Within the header, there is a SafeAreaView which contains two Text components. Notice that we used the style={styles.headerText} prop and style={{...styles.headerText, fontSize:15}}. The reason for this is that we want to have both <Text> components take on the styles of “headerText” and in addition, apply the “fontSize” of 15 onto the second text component. This allows the second text element to be modified without having the other components with the same styling changed.

    Within ScrollView, the data array is mapped over and for each item, a TouchableOpacity component is returned. The key prop is set to the index of the current iteration. The onPress prop navigates to the "DetailPage" when the component is pressed, and the item is passed as a prop. By doing so, it will pass the data of item to the next page we are trying to render.

    Next, we will need to add styling for our components. Styling is what makes your mobile application stand out. The stylings used are similar to CSS.

    Just before the export statement in your IndexPage.js file, add the following code.

    const styles = StyleSheet.create({
      header: {
        backgroundColor: 'green',
        padding: 10,
        borderBottomWidth: 1,
        borderBottomColor: '#ddd',
      },
      headerText: {
        fontSize: 20,
        fontWeight: 'bold',
        color: 'white',
        textAlign:"left"
      },
      image: {
        width: '100%',
        height: 300,
        resizeMode: 'cover'
      },
      innerImage: {
        padding: 10,
        flexDirection: 'row',
        justifyContent: 'space-between',
        alignItems: 'center'
      },
      text: {
        fontSize: 20,
        fontWeight: 'bold',
        color: 'black'
      },
      container: {
        margin: 10,
        backgroundColor: 'white',
        borderRadius: 10,
        overflow: 'hidden',
        shadowColor: '#000',
        shadowOffset: {
          width: 0,
          height: 2
        },
        shadowOpacity: 0.25,
        shadowRadius: 3.84,
        elevation: 5
      }
    });
    JavaScript

    The header (lines 17-22 from IndexPage.js) is defined as a <View> with a background color of green, some padding and a border at the bottom with a color of #ddd. The styles are being referenced from the code sample as shown above.

    To check if you have copied the code over correctly, you can check the image below.

  • Step 6: Adding a New Page

    Before we start working on DetailPage.js, we will need to first reference the file in our App.js file. In Step 3, we used the App.js file as a contents page to index all of the pages we need for this application. Now, we will need to add the following code after line 5 of App.js.

    import DetailPage from './pages/DetailPage';
    JavaScript

    In the above code, we are importing the file that we created in Step 2. After which, we will add the following line of code after line 14.

    <Stack.Screen name="DetailPage" component={DetailPage} options={{headerShown:false}}/>
    JavaScript

    The line of code above indexes "DetailPage" and thus allows us to navigate to it in our IndexPage.js file.

    To check if you added the two lines of code correctly, you can check the image below.

  • Step 7: DetailPage.js

    Now we will be working on the code for the details page. Open DetailPage.js and add the code below.

    import { SafeAreaView, View, StyleSheet, Text, ScrollView, Image, TouchableOpacity, StatusBar } from "react-native";
     
    const DetailPage = ({ route, navigation }) => {
      let item = route.params.item;
      return (
        <ScrollView style={{ flex: 1, height:"100%", backgroundColor:"green", marginTop: StatusBar.currentHeight }} bounces={false}>
          <View style={styles.container}>
            <Image
              style={styles.image}
              source={item.image}
            />
            <Text style={styles.header}>{item.name}</Text>
            <Text style={styles.text}>{item.description}</Text>
            <View style={styles.color}>
              <Text style={styles.text}>Colors</Text>
              <View style={{ flexDirection: "row" }}>
                {item.color.map((color, index) => {
                  return (
                    <View key={index} style={{ ...styles.colorBox, backgroundColor: color }}></View>
                  )
                })}
              </View>
            </View>
            <View style={styles.priceContainer}>
              <Text style={styles.text}>Price: ${item.price}</Text>
              <View >
                <TouchableOpacity style={{ backgroundColor: "green", padding: 10, margin: 10, borderRadius: 5 }}>
                  <Text style={{ color: "white", textAlign: "center" }}>Add to Cart</Text>
                </TouchableOpacity>
              </View>
            </View>
          </View>
        </ScrollView>
      )
    }
    JavaScript

    Above is the code needed for this page. The component is named DetailPage (line 3) that renders a detailed view of a single item. It is a functional component that accepts route and navigation props from the parent component. The item data is passed to this component from the parent component through the route.params.item object (line 4).

    The ScrollView component has a style applied to it (line 6), including a green background color and with the height set to "100%".

    Within the ScrollView component, there is a View component with a "container" style applied (line 7). This container component holds the image of the item being displayed, the item name, the item description, the item's colors and the item's price.

    The image of the item is displayed using an Image component (line 8) and the source is set using the item.image property passed in as a parameter. The item name and description are displayed as Text components using the item.name and item.description properties respectively.

    The item's colours are displayed in a View component (line 14) with a "color" style applied. You may notice we use the map function (line 17) to loop through the color property. This allows us to iterate the various colors in the Content.js file and dynamically show it on the Detail Page.

    Now, add the code below at the end of DetailPage.js.

    const styles = StyleSheet.create({
      image: {
        width: "100%",
        height: 300,
        resizeMode: "cover"
      },
      header: {
        fontSize: 30,
        fontWeight: "bold",
        padding: 10,
        color: "white",
        textAlign: "center",
      },
      text: {
        fontSize: 15,
        padding: 10,
        color: "white"
      },
      colorBox: {
        width: 30,
        height: 30,
        borderRadius: 15,
        margin: 5
      },
      container: {
        backgroundColor: "green",
        height: "100%",
      },
      priceContainer: {
        flexDirection: "row",
        justifyContent: "space-between",
        alignItems: "center"
      }
    });
     
    export default DetailPage;
    JavaScript

    The code above is to add the styling of the components above. In line 56, you may notice that we explicitly define the height and width of the View component in line 19. This is to display the colour options in circles, as shown in the image below. By setting the radius to be exactly half of the View’s height, it will create a circle.

    To check if you have added the code correctly to your file, you can check the image below.

  • Step 8: Check Your Work

    On your phone, you should now be able to see an interface similar to the video shown at the beginning of this tutorial.

    You can also take reference from the files in this GitHub repository to see if you have copied the code correctly. 

Have you completed this tutorial? Click below to mark as complete

Help Center Need help?

Find articles to support you through your journey or chat with our support team.

Help Center